summaryrefslogtreecommitdiffstats
path: root/src/core/file_sys/program_metadata.h
blob: 9f8e74b13a30e8585288dc73712bdcee4abcbbea (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <array>
#include <vector>

#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
#include "core/file_sys/vfs_types.h"

namespace Loader {
enum class ResultStatus : u16;
}

namespace FileSys {

enum class ProgramAddressSpaceType : u8 {
    Is32Bit = 0,
    Is36Bit = 1,
    Is32BitNoMap = 2,
    Is39Bit = 3,
};

enum class ProgramFilePermission : u64 {
    MountContent = 1ULL << 0,
    SaveDataBackup = 1ULL << 5,
    SdCard = 1ULL << 21,
    Calibration = 1ULL << 34,
    Bit62 = 1ULL << 62,
    Everything = 1ULL << 63,
};

/**
 * Helper which implements an interface to parse Program Description Metadata (NPDM)
 * Data can either be loaded from a file path or with data and an offset into it.
 */
class ProgramMetadata {
public:
    using KernelCapabilityDescriptors = std::vector<u32>;

    ProgramMetadata();
    ~ProgramMetadata();

    ProgramMetadata(const ProgramMetadata&) = default;
    ProgramMetadata& operator=(const ProgramMetadata&) = default;

    ProgramMetadata(ProgramMetadata&&) = default;
    ProgramMetadata& operator=(ProgramMetadata&&) = default;

    /// Gets a default ProgramMetadata configuration, should only be used for homebrew formats where
    /// we do not have an NPDM file
    static ProgramMetadata GetDefault();

    Loader::ResultStatus Load(VirtualFile file);
    Loader::ResultStatus Reload(VirtualFile file);

    /// Load from parameters instead of NPDM file, used for KIP
    void LoadManual(bool is_64_bit, ProgramAddressSpaceType address_space, s32 main_thread_prio,
                    u32 main_thread_core, u32 main_thread_stack_size, u64 title_id,
                    u64 filesystem_permissions, u32 system_resource_size,
                    KernelCapabilityDescriptors capabilities);

    bool Is64BitProgram() const;
    ProgramAddressSpaceType GetAddressSpaceType() const;
    u8 GetMainThreadPriority() const;
    u8 GetMainThreadCore() const;
    u32 GetMainThreadStackSize() const;
    u64 GetTitleID() const;
    u64 GetFilesystemPermissions() const;
    u32 GetSystemResourceSize() const;
    const KernelCapabilityDescriptors& GetKernelCapabilities() const;

    void Print() const;

private:
    struct Header {
        std::array<char, 4> magic;
        std::array<u8, 8> reserved;
        union {
            u8 flags;

            BitField<0, 1, u8> has_64_bit_instructions;
            BitField<1, 3, ProgramAddressSpaceType> address_space_type;
            BitField<4, 4, u8> reserved_2;
        };
        u8 reserved_3;
        u8 main_thread_priority;
        u8 main_thread_cpu;
        std::array<u8, 4> reserved_4;
        u32_le system_resource_size;
        u32_le process_category;
        u32_le main_stack_size;
        std::array<u8, 0x10> application_name;
        std::array<u8, 0x40> reserved_5;
        u32_le aci_offset;
        u32_le aci_size;
        u32_le acid_offset;
        u32_le acid_size;
    };

    static_assert(sizeof(Header) == 0x80, "NPDM header structure size is wrong");

    struct AcidHeader {
        std::array<u8, 0x100> signature;
        std::array<u8, 0x100> nca_modulus;
        std::array<char, 4> magic;
        u32_le nca_size;
        std::array<u8, 0x4> reserved;
        union {
            u32 flags;

            BitField<0, 1, u32> is_retail;
            BitField<1, 31, u32> flags_unk;
        };
        u64_le title_id_min;
        u64_le title_id_max;
        u32_le fac_offset;
        u32_le fac_size;
        u32_le sac_offset;
        u32_le sac_size;
        u32_le kac_offset;
        u32_le kac_size;
        INSERT_PADDING_BYTES(0x8);
    };

    static_assert(sizeof(AcidHeader) == 0x240, "ACID header structure size is wrong");

    struct AciHeader {
        std::array<char, 4> magic;
        std::array<u8, 0xC> reserved;
        u64_le title_id;
        INSERT_PADDING_BYTES(0x8);
        u32_le fah_offset;
        u32_le fah_size;
        u32_le sac_offset;
        u32_le sac_size;
        u32_le kac_offset;
        u32_le kac_size;
        INSERT_PADDING_BYTES(0x8);
    };

    static_assert(sizeof(AciHeader) == 0x40, "ACI0 header structure size is wrong");

    // FileAccessControl and FileAccessHeader need loaded per-component: this layout does not
    // reflect the real layout to avoid reference binding to misaligned addresses
    struct FileAccessControl {
        u8 version;
        // 3 padding bytes
        u64_le permissions;
        std::array<u8, 0x20> unknown;
    };

    struct FileAccessHeader {
        u8 version;
        // 3 padding bytes
        u64_le permissions;
        u32_le unk_offset;
        u32_le unk_size;
        u32_le unk_offset_2;
        u32_le unk_size_2;
    };

    Header npdm_header;
    AciHeader aci_header;
    AcidHeader acid_header;

    FileAccessControl acid_file_access;
    FileAccessHeader aci_file_access;

    KernelCapabilityDescriptors aci_kernel_capabilities;
};

} // namespace FileSys